﻿using System;
using System.Collections.Generic;
using System.Text;

using iTextSharp.text;
using iTextSharp.text.pdf;

namespace iPdf
{
    class Navigator
    {
        //The cell width in points
        private const float cellWidth = 70f;
        //The cell height in points
        private const float cellHeight = 13f;
        private const float topOffset = 3f;
        private const float bottomOffset = 17f;

        
        private const int numberOfColumns = 4;
        private const int numberOfPagesToJumpOver = 10;
        private const int minimumNumOfPagesToAddNavigator = numberOfPagesToJumpOver;
        private PdfPTable navigator;
        private PdfPTable firstPageNavigator;
        private PdfPTable lastPageNavigator;
        private iTextSharp.text.Font cellFont = FontFactory.GetFont(BaseFont.HELVETICA, BaseFont.WINANSI,
                                                    BaseFont.NOT_EMBEDDED, 8);

        private static PdfPCell CreateNavigatorCell(Phrase phrase)
        {
            PdfPCell cell = new PdfPCell(phrase);
            cell.FixedHeight = cellHeight;
            cell.BorderWidth = 1f;
            cell.BorderColor = Color.RED;
            cell.UseBorderPadding = true;
            cell.BackgroundColor = Color.BLUE;
            cell.UseBorderPadding = true;
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            
            return cell;
        }

        public Navigator()
        {
            navigator = new PdfPTable(numberOfColumns);
            navigator.TotalWidth = numberOfColumns * cellWidth;
            navigator.DefaultCell.HorizontalAlignment = Element.ALIGN_CENTER;
            PdfPCell firstPage = CreateNavigatorCell( new Phrase(new Chunk("First Page", cellFont)
                .SetAction(new PdfAction(PdfAction.FIRSTPAGE))) );
            PdfPCell prevPage = CreateNavigatorCell(new Phrase(new Chunk("Prev Page", cellFont)
                .SetAction(new PdfAction(PdfAction.PREVPAGE))) );
            PdfPCell nextPage = CreateNavigatorCell(new Phrase(new Chunk("Next Page", cellFont)
                .SetAction(new PdfAction(PdfAction.NEXTPAGE))) );
            PdfPCell lastPage = CreateNavigatorCell(new Phrase(new Chunk("Last Page", cellFont)
                .SetAction(new PdfAction(PdfAction.LASTPAGE))) );

            navigator.AddCell(firstPage);
            navigator.AddCell(prevPage);
            navigator.AddCell(nextPage);
            navigator.AddCell(lastPage);

            firstPageNavigator = new PdfPTable(numberOfColumns / 2);
            firstPageNavigator.TotalWidth = numberOfColumns / 2 * cellWidth;
            firstPageNavigator.AddCell(nextPage);
            firstPageNavigator.AddCell(lastPage);


            lastPageNavigator = new PdfPTable(numberOfColumns / 2);
            lastPageNavigator.TotalWidth = numberOfColumns / 2 * cellWidth;
            lastPageNavigator.AddCell(prevPage);
            lastPageNavigator.AddCell(firstPage);
        }

        public List<PdfPCell> CreateJumpOverCells(PdfStamper stamper, int pageNo, int numberOfPages)
        {
            List<PdfPCell> cells = new List<PdfPCell>();

            if (pageNo > numberOfPagesToJumpOver)
            {
                cells.Add(CreateJumpOverCell(stamper,
                    JumpDirection.Previous, pageNo - numberOfPagesToJumpOver));
            }

            if (pageNo < numberOfPages - numberOfPagesToJumpOver)
            {
                cells.Add( CreateJumpOverCell(stamper, JumpDirection.Next,
                   pageNo + numberOfPagesToJumpOver) );
            }

            return cells;
        }

        public PdfPCell CreateJumpOverCell(PdfStamper stamper, JumpDirection direction, 
            int jumpToPageNo)
        {
            float verticalPos = stamper.Reader.GetCropBox(jumpToPageNo).Height;
            PdfDestination dest = new PdfDestination(PdfDestination.FITH, verticalPos);
            PdfAction action = PdfAction.GotoLocalPage(
                        jumpToPageNo, dest, stamper.Writer);
            Phrase phrase = new Phrase(new Chunk(direction.ToString() + " " + 
                numberOfPagesToJumpOver + " Page", cellFont).SetAction(action));

            return CreateNavigatorCell(phrase);
        }

        public PdfPTable CreateJumpOverNavigator(PdfStamper stamper, int pageNo, int numberOfPages)
        {
            if (numberOfPages > numberOfPagesToJumpOver)
            {
                List<PdfPCell> cells = CreateJumpOverCells(stamper, pageNo, numberOfPages);
                if (cells.Count == 0)
                {
                    return null;
                }

                PdfPTable jumpOverNavigator = new PdfPTable(cells.Count);
                jumpOverNavigator.TotalWidth = cells.Count * cellWidth;
                foreach (PdfPCell cell in cells)
                {
                    jumpOverNavigator.AddCell(cell);
                }

                return jumpOverNavigator;
            }

            return null;
        }

        public void AttachToDocument(PdfStamper stamper)
        {
            PdfReader reader = stamper.Reader;
            int numOfPages = reader.NumberOfPages;
            if (numOfPages < minimumNumOfPagesToAddNavigator)
            {
                return;
            }

            for (int i = 1; i <= numOfPages; ++i)
            {
                AttachToPage(stamper, i, numOfPages);
            }
        }

        private void AttachToPage(PdfStamper stamper, int pageNo, int numOfPages )
        {
            PdfContentByte cb = stamper.GetOverContent(pageNo);
            Rectangle pageRect = stamper.Reader.GetPageSizeWithRotation(pageNo);
            PdfPTable table ;
            if (pageNo == 1)
            {
                table = firstPageNavigator;
            }
            else if (pageNo > 1 && pageNo < numOfPages)
            {
                table = navigator;
            }
            else
            {
                table = lastPageNavigator;
            }

            table.WriteSelectedRows(0, -1,
                (pageRect.Width - table.TotalWidth) / 2, pageRect.Height - topOffset, cb);
            table.WriteSelectedRows(0, -1,
                (pageRect.Width - table.TotalWidth) / 2,
                pageRect.Bottom + bottomOffset, cb);

            PdfPTable jumpOverNavigator = CreateJumpOverNavigator(
                stamper, pageNo, numOfPages);

            if (jumpOverNavigator != null)
            {
                jumpOverNavigator.WriteSelectedRows(0, -1,
                    (pageRect.Width - jumpOverNavigator.TotalWidth) / 2,
                    pageRect.Height - topOffset - table.TotalHeight, cb);
                jumpOverNavigator.WriteSelectedRows(0, -1,
                    (pageRect.Width - jumpOverNavigator.TotalWidth) / 2, 
                    pageRect.Bottom + bottomOffset + table.TotalHeight, cb);
            }
        }
    }
}
